﻿using pdfer.Filters;
using pdfer.Syntax;
using SixLabors.ImageSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace pdfer.FileObjects
{
    internal class PdfFileObject
    {
        protected PdfParser pdfParser;
        public PdfParser PdfParser { set { pdfParser = value; } }
        public PdfFileObject() 
        {
        }
        public PdfFileObject(PdfFileObject obj) 
        {
            No = obj.No;
            Dictionary = obj.Dictionary;
            List = obj.List;
            StreamData = obj.StreamData;
            this.pdfParser = obj.pdfParser;
        }
        /// <summary>
        /// 对象Id 例子：1 0 obj -> 1 0
        /// 可能有不存在标号的字典 比如尾部字典
        /// </summary>
        public string No { get; set; }

        internal Object this[String key]
        {
            get
            {
                return Dictionary[key];
            }
        }

        internal Object this[Int32 key]
        {
            get
            {
                return List[key];
            }
        }

        public Boolean TryGetValue(String key, out Object? val) => Dictionary.TryGetValue(key, out val);

        public PdfFileObject GetIndirectObj(String refId) 
        {
            // 间接引用直接获取对象
            var obj = pdfParser.GetPdfFileObject<PdfFileObject>(refId);
            return obj;
        }

        public T GetIndirectObj<T>(String refId) where T : PdfFileObject
        {
            // 间接引用直接获取对象
            var obj = pdfParser.GetPdfFileObject<T>(refId);
            return obj;
        }

        /// <summary>
        /// 字典对象
        /// </summary>
        public Dictionary<String, Object> Dictionary { get; internal set; }

        /// <summary>
        /// 数组对象
        /// </summary>
        public List<Object> List { get; internal set; }

        public Object Value { get; internal set; }

        /// <summary>
        /// 二进制的数据
        /// </summary>
        public Byte[] StreamData { get; internal set; }

        private Byte[] _rawData;

        private List<String> _filters;
        public List<String> Filters
        {
            get 
            {
                if(_filters == null)
                {
                    _filters = new List<String>();
                    if (TryGetValue(PdfName.Key_Filter, out var _f))
                    {
                        if (_f is IList)
                        {
                            _filters.AddRange(PdfParserUtils.ParseList<String>(_f, PdfParserUtils.Trans2String, this));
                        }
                        else
                        {
                            _filters.Add(PdfParserUtils.ParseString(_f));
                        }
                    }
                }
                return _filters;
            }
        }
        /// <summary>
        /// 解压缩后的二进制数据
        /// </summary>
        public Byte[] DecodeStreamData
        {
            get
            {
                if (_rawData == null)
                {
                    // 如果有过滤器就解压缩
                    // 多个过滤器的怎么处理
                    List<String> filters = Filters;
                    // 按顺序解压缩即可
                    Int32 length = StreamData.Length;
                    if (TryGetValue(PdfName.Key_Length, out var v))
                    {
                        try
                        {
                            var _length = PdfParserUtils.ParseInt32(v, this);
                            length = length > _length ? _length : length;
                        }
                        catch { }
                    }
                    var _tmpData = StreamData.AsSpan().Slice(0, length);
                    PredictorParam dp;
                    for (var i = 0; i < filters.Count; i++)
                    {
                        switch (filters[i])
                        {
                            case IFilter.Name_ASCIIHexDecode:
                            case IFilter.Name_ASCIIHexDecode2:
                                _tmpData = new ASCIIHexDecodeFilter().Decode(_tmpData);
                                break;
                            case IFilter.Name_FlateDecode:
                            case IFilter.Name_FlateDecode2:
                                _tmpData = new FlateDecodeFilter().Decode(_tmpData);
                                // DecodeParams
                                dp = new PredictorParam(this);
                                _tmpData = new PredictorDecodeFilter().Decode(_tmpData, dp);
                                break;
                            case IFilter.Name_ASCII85Decode:
                            case IFilter.Name_ASCII85Decode2:
                                _tmpData = new ASCII85DecodeFilter().Decode(_tmpData);
                                break;
                            case IFilter.Name_LZWDecode:
                            case IFilter.Name_LZWDecode2:
                                _tmpData = new LZWDecodeFilter().Decode(_tmpData);
                                // DecodeParams
                                dp = new PredictorParam(this);
                                _tmpData = new PredictorDecodeFilter().Decode(_tmpData, dp);
                                break;
                            case IFilter.Name_RunLengthDecode:
                            case IFilter.Name_RunLengthDecode2:
                                _tmpData = new RunLengthDecodeFilter().Decode(_tmpData);
                                break;
                            case IFilter.Name_CCITTFaxDecode:
                            case IFilter.Name_CCITTFaxDecode2:
                                var f = new CCITTFaxDecodeFilter();
                                f.Params = new CCITTFaxDecodeParams(this);
                                // 这里只是补充了可以让处理tiff解码器的程序读取图像数据的必要文件头和IFD数据
                                // 实际上还是没有解码的数据
                                _tmpData = f.Recover(_tmpData);
                                break;
                            case IFilter.Name_JBIG2Decode:
                            case IFilter.Name_JPXDecode:
                            case IFilter.Name_DCTDecode:
                            case IFilter.Name_DCTDecode2:
                                // 图像不在这里处理
                                break;
                            case IFilter.Name_Crypt:
                                break;
                            default:
                                throw new NotImplementedException($"不支持的解码器: {filters[i]}");
                        }
                    }
                    _rawData = _tmpData.ToArray();
                }

                return _rawData;
            }
        }


        #region ParseToType
        protected PdfFileObject GetDicPdfFileObjVal(String key, PdfFileObject val = null)
        {
            if (TryGetValue(key, out var _val) && _val is String __val && __val.EndsWith('R'))
            {
                var _obj = GetIndirectObj(__val);
                return _obj;
            }
            return val;
        }

        protected T GetDicPdfFileObjVal<T>(String key, T val = null)where T : PdfFileObject
        {
            if (TryGetValue(key, out var _val) && _val is String __val && __val.EndsWith('R'))
            {
                var _obj = GetIndirectObj<T>(__val);
                return _obj;
            }
            return val;
        }

        protected String GetDicStringVal(String key, String val = null)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseString(_val);
            }
            return val;
        }
        
        protected Boolean GetDicBooleanVal(String key, Boolean val = false)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseBoolean(_val);
            }
            return val;
        }

        protected Int32 GetDicInt32Val(String key, Int32 val = 0)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseInt32(_val, val);
            }
            return val;
        }

        protected Double GetDicDoubleVal(String key, Double val = 0)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseDouble(_val);
            }
            return val;
        }

        protected List<Object>? GetDicListVal(String key)
            => GetDicListVal<Object>(key, PdfParserUtils.Trans2Object);

        protected List<T>? GetDicListVal<T>(String key, Func<Object, T> trans)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseList(_val, trans);
            }
            return null;
        }

        protected Dictionary<String, Object>? GetDicDictionaryVal(String key)
        {
            if (TryGetValue(key, out var _val))
            {
                return ParseDictionary(_val);
            }
            return null;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected Boolean ParseBoolean(Object obj)
        {
            if (obj is String str)
            {
                if (str.EndsWith(" R"))
                {
                    var _obj = GetIndirectObj(str);
                    if (_obj.Value != null && _obj.Value is Boolean v)
                    {
                        return v;
                    }
                    return default;
                }
                else
                {
                    _ = Boolean.TryParse(obj?.ToString(), out var val);
                    return val;
                }
            }
            return false;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected Int32 ParseInt32(Object obj, Int32? defval = null)
        {
            if (obj is String str)
            {
                if (str.EndsWith(" R"))
                {
                    var _obj = GetIndirectObj(str);
                    if (_obj.Value != null && _obj.Value is Int32 v)
                    {
                        return v;
                    }
                    return default;
                }
                else
                {
                    _ = Int32.TryParse(obj?.ToString(), out var val);
                    return val;
                }
            }
            return defval ?? default;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected Double ParseDouble(Object obj)
        {
            if (obj is String str)
            {
                if (str.EndsWith(" R"))
                {
                    var _obj = GetIndirectObj(str);
                    if (_obj.Value != null && _obj.Value is Double v)
                    {
                        return v;
                    }
                    return default;
                }
                else
                {
                    _ = Double.TryParse(obj?.ToString(), out var val);
                    return val;
                }
            }
            return default;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected List<T>? ParseList<T>(Object val, Func<Object, T> trans)
        {
            if (val is IList<T> _val)
            {
                return _val.ToList();
            }
            else if (val is IList _val2)
            {
                var re = new List<T>(_val2.Count);
                foreach (var item in _val2)
                {
                    re.Add(trans(item));
                }
                return re;
            }
            else if (val is PdfFileObject _val3)
            {
                var re = new List<T>(_val3.List.Count);
                foreach (var item in _val3.List)
                {
                    re.Add(trans(item));
                }
                return re;

            }
            else if (val is String str && str.EndsWith(" R"))
            {
                var obj = GetIndirectObj(str);
                if(obj.List == null)
                {
                    return [];
                }
                var re = new List<T>(obj.List.Count);
                foreach (var item in obj.List)
                {
                    re.Add(trans(item));
                }
                return re;
            }
            return val == null ? null : [];
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected Dictionary<String, Object>? ParseDictionary(Object val)
        {
            if (val is Dictionary<String, Object> _val)
            {
                return _val;
            }
            else if (val is PdfFileObject fileObject)
            {
                return fileObject.Dictionary;
            }
            else if (val is String str && str.EndsWith(" R"))
            {
                var obj = GetIndirectObj(str);
                return obj.Dictionary;
            }
            return val == null ? null : [];
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected String? ParseString(Object obj)
        {
            var str = obj?.ToString();
            if (str == null)
            {
                return null;
            }
            if (str[0] == '(')
            {
                return str[1..^1];
            }
            else if (str[0] == '<')
            {
                // TODO 对于16进制表示的字符串需要处理
                return str[1..^1];
            }
            else if(str[^1] == 'R')
            {
                var _obj = GetIndirectObj(str);
                return _obj.Value.ToString();
            }
            else
            {
                return str;
            }
        }
        #endregion
    }
}
